/*
 * ResultCanvas.java
 * Implement the MIDP canvas class where Jupiter and its moons will be drawn.
 *
 * Copyright 2009 by Miguel Moreto.
 * You may use or distribute this code under the terms of the GPL.
 *
 * $Rev: 54 $
 * $LastChangedDate: 2009-07-15 14:22:06 +0000 (Wed, 15 Jul 2009) $
 */

package Main;

import javax.microedition.lcdui.*;
import java.util.*;

/**
 * @author moreto
 */
public class ResultCanvas extends Canvas implements CommandListener {
    /**
     * constructor
     */
    private Calendar calendar = Calendar.getInstance();
    private long originalDateMilliseconds;
    private long currentDateMilliseconds;
    private long tzoneOffsetMilliseconds = 0;
    private int tzoneOffset = 0;
    private int year;
    private int month;
    private int day;
    private int hour;
    private int minute;
    private int seconds;
    private int ia = 0;
    private boolean invertVerticalFlag = false;
    private boolean invertHorizontalFlag = false;
    private boolean invertAllFlag = false;
    private boolean invertFlag = false;
    private double angle = Math.PI/2;
    private double angleInc = Math.PI/40;
    double xcenter = 0.5;
    double ycenter = 0.5;
    double positionInc = 0.025; // Default increment for position.
    private boolean modeFlag = true; // true = time mode, false = navigate mode.
    private double zoom = 1;
    private double zoomFactor = 1.5;
    private int userTimeInc = 60;
    //private int tzoneOffset = 0;
    Jupiter jupiter;

/*    public ResultCanvas() {
    }*/
    
    /**
     * paint method
     */
    public void paint(Graphics g) {

        int width = getWidth();
        int height = getHeight();
        int xc = (int)((double)width * xcenter);
    	int yc = (int)((double)height * ycenter);

        // Filling the canvas with a black rectangle:
        g.fillRect(0, 0, width, height );
        g.setColor (255, 0, 0);

        Font font = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_PLAIN,Font.SIZE_SMALL);

        g.setFont(font);
        int moonRadius = 2;

        screenCoords data1 = new screenCoords(width,height,xc,yc,moonRadius,zoom,4);

        boolean flag = false;
        if (ia == 90){
            flag = true;
        }

        StarDate tst = new StarDate(currentDateMilliseconds);
        if (jupiter == null)
            jupiter = new Jupiter(tst,flag);
        else
            jupiter.setTopFlag(flag);
            jupiter.setDate(tst);

        // Using Akklets:
        XYCoord coord;

        int whichmoon;
        for (whichmoon=0; whichmoon < jupiter.getNumMoons(); ++whichmoon){
            // See if this moon is casting a shadow:
            coord = jupiter.getMoonShadowXY(whichmoon);
            if (coord.x != Double.POSITIVE_INFINITY && coord.y != Double.POSITIVE_INFINITY)
                {
                data1.appendData(coord.x, coord.y, jupiter.getMoonLabel(whichmoon), jupiter.getMoonDist(whichmoon), true);
                }
            coord = jupiter.getMoonXY(whichmoon);
            if ((coord.x != Double.POSITIVE_INFINITY) && (coord.y != Double.POSITIVE_INFINITY))
                {
                data1.appendData(coord.x, coord.y, jupiter.getMoonLabel(whichmoon), jupiter.getMoonDist(whichmoon), false);
                }
        }

        // Drawing time and date text:
        String str1 = String.valueOf(hour)+":"+String.valueOf(minute)+":"+String.valueOf(seconds)+"h";
        String str2 = String.valueOf(day)+"/"+String.valueOf(month)+"/"+String.valueOf(year);
        g.drawString(str1 + " (UT)", width, 0, Graphics.TOP|Graphics.RIGHT);
        g.drawString("GMT " +String.valueOf(tzoneOffset) , width, 15, Graphics.TOP|Graphics.RIGHT);
        g.drawString(str2, 1, height, Graphics.BOTTOM|Graphics.LEFT);
        if (modeFlag){
            g.drawString("TimeMode",1, height-15, Graphics.BOTTOM|Graphics.LEFT);
        }else{
            g.drawString("ViewMode",1, height-15, Graphics.BOTTOM|Graphics.LEFT);
        }

        if (angle == -1){
            angle = mMath.atan((double)width/(double)height);
        }

        if (invertFlag){
            data1.invertHorizontal();
            data1.invertVertical();
        }
        // The draw should be horizontal inverted?
        if (invertHorizontalFlag == true && ia == 0){
            data1.invertHorizontal();
        }
        // The draw should be vertical inverted?
        if (invertVerticalFlag == true && ia == 0){
            data1.invertVertical();
        }
        // The draw should be all inverted?
        if (invertAllFlag == true && ia == 0){
            data1.invertHorizontal();
            data1.invertVertical();
        }

        data1.calculateScreenCoords(angle); // Calculate the screen coordinates

        //int x1=(int)data1.getScreenXcoord(0);
        //System.out.println("x1: " + String.valueOf(x1));
        //int y1=(int)data1.getScreenYcoord(0);
        //System.out.println("y1: " + String.valueOf(y1));
        //int x2=(int)data1.getScreenXcoord(1);
        //System.out.println("x2: " + String.valueOf(x2));
        //int y2=(int)data1.getScreenYcoord(1);
        //System.out.println("y2: " + String.valueOf(y2));
        //g.drawLine(x1, y1, x2, y2);

        int js;
        js = data1.getJs();
        g.fillArc(xc-js,yc-js, 2*js, 2*js, 0, 360);

        boolean namesPosFlag = true;
        int yt = 0;
        int xt = 0;

        for (int i=0; i<data1.getSize(); i++){

            if (data1.getType(i)){ // If it is a shadow, draw it in green color.
                g.setColor(0,255,255);
            }
            int xscr = (int)(data1.getScreenXcoord(i+2));
            int yscr = (int)(data1.getScreenYcoord(i+2));
            g.fillArc(xscr, yscr, 2*moonRadius, 2*moonRadius,0,360);
            // Placing the moon labels text:
            if (namesPosFlag){
                if (angle > Math.PI/4){
                    yt = yscr + 6;
                    xt = xscr;
                }else{
                    yt = yscr;
                    xt = xscr + 18;
                }
                namesPosFlag = false;
            }else{
                if (angle > Math.PI/4){
                    yt = yscr - 18;
                    xt = xscr;
                }else{
                    yt = yscr;
                    xt = xscr - 18;
                }
                namesPosFlag = true;
            }

            String name = data1.getName(i);

            if (xscr >= (width - font.stringWidth("XX"))){ // If is near right margin:
                if (yscr >= (height - 20)){
                    g.drawString(name, xt, yt, Graphics.BOTTOM|Graphics.RIGHT);
                }else{
                    g.drawString(name, xt, yt, Graphics.TOP|Graphics.RIGHT);
                }
            }else if (xscr <= (font.stringWidth("XX"))){// If is near left margin:
                if (yscr >= (height - 20)){
                    g.drawString(name, xt, yt, Graphics.BOTTOM|Graphics.LEFT);
                }else{
                    g.drawString(name, xt, yt, Graphics.TOP|Graphics.LEFT);
                }
            }else{ // Otherwise:
                if (yscr >= (height - 20)){
                    g.drawString(name, xt, yt, Graphics.BOTTOM|Graphics.HCENTER);
                }else{
                    if (angle > Math.PI/4){
                        g.drawString(name, xt, yt, Graphics.TOP|Graphics.HCENTER);
                    }else{
                        g.drawString(name, xt, yt-8, Graphics.TOP|Graphics.HCENTER);
                    }
                }
            }
            g.setColor (255, 0, 0);

            int radius = (int)(data1.getRadius(i)*js);
            
            // Drawing orbital paths:
            if (ia == 90){
                g.drawArc(xc-radius, yc-radius, 2 * radius, 2 * radius, 0, 360);
            }
        }


        if (ia == 0){ // Show arrow only in frontal view:
            drawArrow(g,20,30,10,width/4,3*height/4,angle+Math.PI/2);
            if (invertFlag){
                g.drawString("N", width/6, 3*height/4, Graphics.TOP|Graphics.HCENTER);
            }else{
                g.drawString("S", width/6, 3*height/4, Graphics.TOP|Graphics.HCENTER);
            }
        }
    }

    public void updateCanvas(){
        repaint();
    }

    //<editor-fold defaultstate="collapsed" desc=" drawArrow method ">
    /*
     * Draw an arrow that can be rotated;
     * tw= triangle head width (size of the side of triangle);
     * rh= width of the arrow tail;
     * rh= height of the arrow tail;
     * Xcenter and Ycenter = center of the arrow;
     */
    private void drawArrow(Graphics g,int tw, int rh, int rw, int Xcenter,
            int Ycenter, double angle){

        double th = ((double)tw*Math.sqrt(3))/2;
        double hr = Math.sqrt((rw*rw)/4 + rh*rh); // diagonal of the arrow tail.
        double beta = mMath.atan((double)rw/2/(double)rh);

        double ang1s = Math.sin(3*Math.PI/2+angle);
        double ang1c = Math.cos(3*Math.PI/2+angle);
        double ang2s = Math.sin(Math.PI/2+angle);
        double ang2c = Math.cos(Math.PI/2+angle);

        int ax = Xcenter - (int)(th*Math.sin(angle));
        int ay = Ycenter - (int)(th*Math.cos(angle));
        int bx = Xcenter - (int)((((double)tw)/2)*ang1s);
        int by = Ycenter - (int)((((double)tw)/2)*ang1c);
        int cx = Xcenter - (int)((((double)tw)/2)*ang2s);
        int cy = Ycenter - (int)((((double)tw)/2)*ang2c);
        int dx = Xcenter - (int)((((double)rw)/2)*ang2s);
        int dy = Ycenter - (int)((((double)rw)/2)*ang2c);
        int ex = Xcenter - (int)((((double)rw)/2)*ang1s);
        int ey = Ycenter - (int)((((double)rw)/2)*ang1c);

        int fx = Xcenter - (int)(hr*Math.sin(Math.PI+angle-beta));
        int fy = Ycenter - (int)(hr*Math.cos(Math.PI+angle-beta));
        int gx = Xcenter - (int)(hr*Math.sin(Math.PI+angle+beta));
        int gy = Ycenter - (int)(hr*Math.cos(Math.PI+angle+beta));
        // nao e rw/2
        // Arrow head:
        g.fillTriangle(ax, ay, bx, by, cx, cy);
        // Arrow tail:
        g.fillTriangle(dx, dy, ex, ey, fx, fy);
        g.fillTriangle(ex, ey, gx, gy, fx, fy);
    }
    //</editor-fold>

    public void setInvertHorizontalFlag(boolean status){
        invertHorizontalFlag = status;
    }

    public void setInvertVerticalFlag(boolean status){
        invertVerticalFlag = status;
    }

    public void setInvertAllFlag(boolean status){
        invertAllFlag = status;
    }

    /*
     * Setting the screen rotation angle.
     *  index = 0 => horizontal (angle = 90);
     *  index = 1 => vertical (angle = 0);
     *  index = 2 => diagonal (angle = -1).
     */
    public void setAngle(int index){
        switch (index) {
            case 0:
                angle = Math.PI/2;
                break;
            case 1:
                angle = 0;
                break;
            case 2:
                angle = -1;
                break;
        }
    }

    public void setUserTimeInc(int increment){
        userTimeInc = increment;
    }

//<editor-fold defaultstate="collapsed" desc=" setDate method ">
    /*
     * Initial date setter method used to plot the orbits.
     *
     * d = date in milliseconds;
     * tzoneOffset = signed offset from GMT in hours.
     */
    public void setDate(long d,int tzOffset){
        // Converting the date in milliseconds to a date object and
        // creating a calendar object.

        tzoneOffset = tzOffset;
        tzoneOffsetMilliseconds = 60 * 60 * 1000 * (long)tzOffset;
        originalDateMilliseconds = d  - tzoneOffsetMilliseconds;
        currentDateMilliseconds = d  - tzoneOffsetMilliseconds;

        calendar.setTime(new Date(originalDateMilliseconds));

        //TimeZone tzone = TimeZone.getTimeZone("GMT");
        //tzoneOffset = tzone.getRawOffset();

        //calendar.setTimeZone(tzone);

        year = calendar.get(calendar.YEAR);
        month = calendar.get(calendar.MONTH) + 1;
        day = calendar.get(calendar.DAY_OF_MONTH);
        hour = calendar.get(calendar.HOUR_OF_DAY);
        minute = calendar.get(calendar.MINUTE);
        seconds = calendar.get(calendar.SECOND);
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="setTimeZoneOffset method ">
    /*
     * Set the time zone offset given in hours (with sign).
     */
    public void setTimeZoneOffset(int offset){
        tzoneOffsetMilliseconds = 60 * 60 * 1000 * (long)offset;
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" incrementDate method ">
    /*
     * Increment the plotting date by inc milliseconds
     */
    public void incrementDate(long inc){

        calendar.setTime(new Date(currentDateMilliseconds + inc));

        currentDateMilliseconds = currentDateMilliseconds + inc;

        //TimeZone tzone = TimeZone.getTimeZone("GMT");
        //tzoneOffset = tzone.getRawOffset();

        //calendar.setTimeZone(tzone);

        year = calendar.get(calendar.YEAR);
        month = calendar.get(calendar.MONTH) + 1;
        day = calendar.get(calendar.DAY_OF_MONTH);
        hour = calendar.get(calendar.HOUR_OF_DAY);
        minute = calendar.get(calendar.MINUTE);
        seconds = calendar.get(calendar.SECOND);
    }
//</editor-fold>

    /*
     * Increment screen rotation angle (rotates counterclockwise)
     */
    public void incrementAngle(){
        if ((angle + angleInc) >= Math.PI/2){
            angle = Math.PI/2;
        }else{
            angle = angle + angleInc;
        }
    }

    /*
     * Decrement screen rotation angle (rotates clockwise)
     */
    public void decrementAngle(){
        if ((angle - angleInc) <= 0){
            angle = 0;
        }else{
            angle = angle - angleInc;
        }
    }
//<editor-fold defaultstate="collapsed" desc=" keyPressed method ">
    /**
     * Called when a key is pressed.
     */
    protected  void keyPressed(int keyCode) {

        switch (keyCode){
            case KEY_STAR: // Key *, change view angle.
                if (ia == 0){
                    ia =  90;
                }else{
                    ia = 0;
                }
                break;
            case KEY_POUND:
                if (modeFlag == true){
                    modeFlag = false;
                }else{
                    modeFlag = true;
                }
                break;
            case KEY_NUM6:
                if (modeFlag == true){
                    incrementDate(30 * 60 * 1000); // Increment 1/2 hour;
                }else{
                    xcenter = xcenter + positionInc;
                }
                break;
            case KEY_NUM4:
                if (modeFlag == true){
                    incrementDate(- 30 * 60 * 1000); // Decrement 1/2 hour;
                }else{
                    xcenter = xcenter - positionInc;
                }
                break;
            case KEY_NUM9: // Increment 1 day;
                if (modeFlag == true){
                    incrementDate(userTimeInc * 60 * 1000);
                }
                break;
            case KEY_NUM0:
                if (invertFlag){
                    invertFlag = false;
                }else{
                    invertFlag = true;
                }
                break;
            case KEY_NUM7: // Decrement 1 day;
                if (modeFlag == true){
                    incrementDate(- userTimeInc * 60 * 1000);
                }
                break;
            case KEY_NUM8:
                if (modeFlag == true){

                }else{
                    ycenter = ycenter + positionInc;
                }
                break;
            case KEY_NUM5: // Reset to preset date;
                 if (modeFlag == true){
                    setDate(System.currentTimeMillis(), tzoneOffset);
                 }else{
                     ycenter = 0.5;
                     xcenter = 0.5;
                 }
                break;
            case KEY_NUM2:
                if (modeFlag == true){
                    zoom = 1;
                }else{
                    ycenter = ycenter - positionInc;
                }
                break;
            case KEY_NUM1:
                if (modeFlag == true){
                    zoom = zoom / zoomFactor;
                }else{
                    incrementAngle();
                }
                break;
            case KEY_NUM3:
                if (modeFlag == true){
                    zoom = zoom * zoomFactor;
                }else{
                    decrementAngle();
                }
                break;
 /*           case UP:
                ycenter = ycenter + positionInc;
                break;
            case DOWN:
                ycenter = ycenter - positionInc;
                break;
            case LEFT:
                xcenter = xcenter - positionInc;
                break;
            case RIGHT:
                xcenter = xcenter + positionInc;
                break;*/

        }
        repaint();
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" keyReleased method ">
    /**
     * Called when a key is released.
     */
    protected  void keyReleased(int keyCode) {
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" keyRepeated method ">
    /**
     * Called when a key is repeated (held down).
     */
    protected  void keyRepeated(int keyCode) {
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" pointerDragged method ">
    /**
     * Called when the pointer is dragged.
     */
    protected  void pointerDragged(int x, int y) {
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" pointerPressed method ">
    /**
     * Called when the pointer is pressed.
     */
    protected  void pointerPressed(int x, int y) {
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" pointerReleased method ">
    /**
     * Called when the pointer is released.
     */
    protected  void pointerReleased(int x, int y) {
    }
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc=" commandAction method ">
    /**
     * Called when action should be handled
     */
    public void commandAction(Command command, Displayable displayable) {
    }
//</editor-fold>

}